package classes.graphicalEngine
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.Point;
	
	import mx.collections.*;
	import mx.core.*;
	
	public class GameObjectManager
	{
		// double buffer
		public var backBuffer:BitmapData;
		// colour to use to clear backbuffer with 
		public var clearColor:uint = 0xFF85dd53;//old color : 0xFF0043AB
		
		public static var landSquaresCollection:ArrayCollection;// la map entière au format xml
		public static var visibleMap:ArrayCollection;// le résultat de GameObjectManager.getFilteredLandSquaresFromMap()
		// array of booleans : an address cell is false if empty, true if occupied
		public static var carteGPS:Array;
		public static var GPS:Astar = new Astar();

		// default dimensions
		public static var defaultMapWidth:Number = 640;
		public static var defaultMapHeight:Number = 480;
		public static var fullSizeMapWidth:Number = 1280;
		public static var fullSizeMapHeight:Number = 960;
		public static var defaultGrapicsSizeMultiple:Number = 32;
		
//		public static var playerCamera:GameCamera;
//		public static var cameraPosition:Point;
		public static var needToBeRefreshed:Boolean = false; 
		// static instance 
		protected static var instance:GameObjectManager = null;
		// the last frame time 
		protected var lastFrame:Date;
		// a collection of the GameObjects 
		protected var gameObjects:ArrayCollection = new ArrayCollection();
		// a collection where new GameObjects are placed, to avoid adding items 
		// to gameObjects while in the gameObjects collection while it is in a loop
		protected var newGameObjects:ArrayCollection = new ArrayCollection();
		// a collection where removed GameObjects are placed, to avoid removing items 
		// to gameObjects while in the gameObjects collection while it is in a loop
		protected var removedGameObjects:ArrayCollection = new ArrayCollection();
		
		public var maCamera:GameCamera;
		
		static public function get Instance():GameObjectManager
		{
			if ( instance == null )
			instance = new GameObjectManager();
			return instance;
		}
		
		public function GameObjectManager()
		{
			if ( instance != null )
				throw new Error( "Only one Singleton instance should be instantiated" ); 
				
		}
		
		public function startup():void
		{
			backBuffer = new BitmapData(defaultMapWidth, defaultMapHeight, false, clearColor);

			lastFrame = new Date();
			maCamera  = new GameCamera();
			carteGPS = new Array(fullSizeMapHeight/defaultGrapicsSizeMultiple);
			for (var y:int = 0; y < carteGPS.length; y++)
			{
				carteGPS[y] = new Array(fullSizeMapWidth/defaultGrapicsSizeMultiple);
				for (var x:int = 0; x < carteGPS[y].length; x++)
				{
					carteGPS[y][x] = 0;
				}
			}
		}
		
		public function shutdown():void
		{
			shutdownAll();
		}
		
		public function enterFrame():void
		{
			// Calculate the time since the last frame
			var thisFrame:Date = new Date();
			var seconds:Number = (thisFrame.getTime() - lastFrame.getTime())/1000.0;
	    	lastFrame = thisFrame;
	    	
	    	// remove the GameObjects that are in the removedGameObjects Array from the gameObjects Array
	    	removeDeletedGameObjects();
	    	// insert the newGameObjects acording to their z position
	    	insertNewGameObjects();
	    	
	    	Level.Instance.enterFrame(seconds);
	    	maCamera.enterFrame(seconds);
	    	
	    	// now allow objects to update themselves
			for each (var gameObject:GameObject in gameObjects)
			{
				if (gameObject.inuse) 
					gameObject.enterFrame(seconds);
				// impossible d'en profiter pour redraw car si on doit 
				// redraw un objet en cours, il faut également redraw
				// tous les objets precedemments vus dans la boucle...
			}
	    	
	    	if (needToBeRefreshed)
	    	{
	    		drawObjects();
	    	}
		}
		
		public function click(event:MouseEvent):void
		{
			maCamera.click(event);
			for each (var gameObject:GameObject in gameObjects)
			{
				if (gameObject.inuse) gameObject.click(event);
			}
		}
		
		public function mouseDown(event:MouseEvent):void
		{
			for each (var gameObject:GameObject in gameObjects)
			{
				if (gameObject.inuse) gameObject.mouseDown(event);
			}
		}
		
		public function mouseUp(event:MouseEvent):void
		{
			for each (var gameObject:GameObject in gameObjects)
			{
				if (gameObject.inuse) gameObject.mouseUp(event);
			}
		}
		
		public function mouseMove(event:MouseEvent):void
		{
			for each (var gameObject:GameObject in gameObjects)
			{
				if (gameObject.inuse) gameObject.mouseMove(event);
			}
		}
		
		protected function drawObjects():void
		{
			backBuffer.fillRect(backBuffer.rect, clearColor);
			
			// draw the objects
			for each (var gameObject:GameObject in gameObjects)
			{
				if (gameObject.inuse) 
					gameObject.copyToBackBuffer(backBuffer);
			}
		}
		
		
		public function addGameObject(gameObject:GameObject):void
		{
			newGameObjects.addItem(gameObject);
		}
		
		public function removeGameObject(gameObject:GameObject):void
		{
			removedGameObjects.addItem(gameObject);
		}
		
		public function shutdownAll():void
		{
			// don't dispose objects twice
			for each (var gameObject:GameObject in gameObjects)
			{
				var found:Boolean = false;
				for each (var removedObject:GameObject in removedGameObjects)
				{
					if (removedObject == gameObject)
					{
						found = true;
						break;
					}
				}
				
				if (!found)
					gameObject.shutdown();
			}
		}
		
		protected function insertNewGameObjects():void
		{
			// insert the object acording to it's z position
			for each (var gameObject:GameObject in newGameObjects)
			{
				var i:int;
				for (i = 0; i < gameObjects.length; ++i)
				{
					if (gameObjects.getItemAt(i).zOrder > gameObject.zOrder ||
						gameObjects.getItemAt(i).zOrder == -1)
						break;
				}

				gameObjects.addItemAt(gameObject, i);
			}
			
			newGameObjects.removeAll();
		}
		
		protected function removeDeletedGameObjects():void
		{
			for each (var removedObject:GameObject in removedGameObjects)
			{
				var i:int = 0;
				for (i = 0; i < gameObjects.length; ++i)
				{
					if (gameObjects.getItemAt(i) == removedObject)
					{
						gameObjects.removeItemAt(i);
						break;
					}
				}
				
			}
			removedGameObjects.removeAll();
		}
		
		public static function getFilteredLandSquaresFromMap(startingCameraPosition:Point):ArrayCollection
		{
			var filteredLandSquares:ArrayCollection = new ArrayCollection();
			for (var i:int = 0; i < GameObjectManager.landSquaresCollection.length; i++)
			{
				/*
				if (GameObjectManager.landSquaresCollection[i].X >= startingCameraPosition.x - GameObjectManager.defaultMapWidth / 4 &&
					GameObjectManager.landSquaresCollection[i].X < startingCameraPosition.x + 5* GameObjectManager.defaultMapWidth / 4 &&
					GameObjectManager.landSquaresCollection[i].Y >= startingCameraPosition.y - GameObjectManager.defaultMapHeight / 4 &&
					GameObjectManager.landSquaresCollection[i].Y < startingCameraPosition.y + 5 * GameObjectManager.defaultMapHeight / 4)
				{
					filteredLandSquares.addItem(GameObjectManager.landSquaresCollection[i]);
				}
				*/
				filteredLandSquares.addItem(GameObjectManager.landSquaresCollection[i]);
			}
			return filteredLandSquares;
		}
	}
}